#include "./StrFunc.h"

char *Str_clone(const char *str)
{
    int size = strlen(str);
    char *res = malloc((size + 1) * sizeof(char));
    strcpy(res, str);
    return res;
}

char *Str_add(const char *str1, const char *str2)
{
    int size = strlen(str1) + strlen(str2);
    char *res = malloc((size + 1) * sizeof(char));
    strcpy(res, str1);
    strcat(res, str2);
    return res;
}

char *Str_addFree(char *str1, char *str2)
{
    char *res = Str_add(str1, str2);
    free(str1);
    free(str2);
    return res;
}

/**
 * @brief pattern长度级别的单次匹配
 */
int Str_matchOne(const char *origin, int offset, const char *pattern)
{
    for (int i = 0; pattern[i]; i++)
        if (origin[offset + i] != pattern[i])
            return 0;
    return 1;
}

char *newChar(char c)
{
    char *p = malloc(sizeof(char));
    *p = c;
    return p;
}

char *Str_ListNode(ListNode *p)
{
    return p->ptr;
}

/**
 * @param p 受拼接的字符链表，拼接完成后p清空但不销毁
 */
char *Str_fromCharListType(ListType *p)
{
    char *str = malloc((p->size + 1) * sizeof(char));
    int nn = 0;
    while (p->size)
    {
        str[nn++] = *Str_ListNode(p->head);
        ListType_remove(p, p->head);
    }
    str[nn] = 0;
    return str;
}

ListType *Str_split(const char *origin, const char *pattern, int keepQuotationMarks)
{
    int patternSize = strlen(pattern);
    int inside = 0;
    /**
     * @brief 所有权带出函数
     *
     */
    ListType *res = ListType_ListType(free);
    /**
     * @brief 所有权内部销毁
     *
     */
    ListType *tmp = ListType_ListType(free);
    for (int i = 0; origin[i]; i++)
    {
        if (inside)
        {
            if (Str_matchOne(origin, i, "\"\""))
            {
                ListType_insert(tmp, NULL, newChar('\"'));
                if (keepQuotationMarks)
                    ListType_insert(tmp, NULL, newChar('\"'));
                i++;
            }
            else if (origin[i] == '\"')
            {
                inside = 0;
                if (keepQuotationMarks)
                    ListType_insert(tmp, NULL, newChar('\"'));
            }
            else
            {
                ListType_insert(tmp, NULL, newChar(origin[i]));
            }
        }
        else
        {
            if (origin[i] == '\"')
            {
                inside = 1;
                if (keepQuotationMarks)
                    ListType_insert(tmp, NULL, newChar('\"'));
            }
            else if (Str_matchOne(origin, i, pattern))
            {
                ListType_insert(res, NULL, Str_fromCharListType(tmp));
                i += patternSize - 1;
            }
            else
            {
                ListType_insert(tmp, NULL, newChar(origin[i]));
            }
        }
    }
    ListType_insert(res, NULL, Str_fromCharListType(tmp));
    ListType_free(tmp);
    return res;
}

char *Str_CSVMode(const char *origin)
{
    ListType *list = ListType_ListType(free);
    ListType_insert(list, NULL, newChar('\"'));
    for (int i = 0; origin[i]; i++)
    {
        ListType_insert(list, NULL, newChar(origin[i]));
        if (origin[i] == '\"')
            ListType_insert(list, NULL, newChar('\"'));
    }
    ListType_insert(list, NULL, newChar('\"'));
    char *res = Str_fromCharListType(list);
    ListType_free(list);
    return res;
}

char *Str_CSVModeFree(char *origin)
{
    char *res = Str_CSVMode(origin);
    free(origin);
    return res;
}

char *Str_join(ListType *list, const char *split)
{
    int len = 0;
    int splitLen = strlen(split);
    for (ListNode *ite = list->head; ite; ite = ite->next)
    {
        len += strlen(Str_ListNode(ite));
        if (ite != list->tail)
            len += splitLen;
    }
    char *res = malloc((len + 1) * sizeof(char));
    int p = 0;
    for (ListNode *ite = list->head; ite; ite = ite->next)
    {
        strcpy(res + p, Str_ListNode(ite));
        p += strlen(Str_ListNode(ite));
        if (ite != list->tail)
        {
            strcpy(res + p, split);
            p += splitLen;
        }
    }
    res[p] = 0; // 针对空链表
    return res;
}

char *Str_fromFile(const char *filename)
{
    FILE *file = fopen(filename, "r");
    if (!file)
    {
        printf("无法打开文件\"%s\"。", filename);
        return newChar(0);
    }
    ListType *list = ListType_ListType(free);
    int c;
    while ((c = fgetc(file)) != EOF)
        ListType_insert(list, NULL, newChar(c));
    char *res = Str_fromCharListType(list);
    ListType_free(list);
    fclose(file);
    return res;
}

void Str_toFile(const char *str, const char *filename)
{
    FILE *file = fopen(filename, "w");
    if (!file)
    {
        printf("无法写入文件\"%s\"。", filename);
        return;
    }
    fprintf(file, "%s", str);
    fclose(file);
}

double Str_parseDouble(const char *str)
{
    double res;
    sscanf(str, "%lf", &res);
    return res;
}

double Str_parseDoubleFree(char *str)
{
    double res = Str_parseDouble(str);
    free(str);
    return res;
}

int Str_parseInt(const char *str)
{
    int res;
    sscanf(str, "%d", &res);
    return res;
}

int Str_parseIntFree(char *str)
{
    int res = Str_parseInt(str);
    free(str);
    return res;
}

char *Str_fromDouble(double v, int fixed)
{
    static char c[103];
    sprintf(c, "%.*lf", fixed, v);
    return Str_clone(c);
}

char *Str_fromInt(int v)
{
    static char c[103];
    sprintf(c, "%ld", v);
    return Str_clone(c);
}

int Str_isSpace(const char *str)
{
    int spaceFlag = 1;
    for (int i = 0; str[i]; i++)
    {
        if (!isspace(str[i]))
            spaceFlag = 0;
    }
    return spaceFlag;
}

int Str_indexOf(const char *str, const char *pattern)
{
    for (int i = 0; str[i]; i++)
        if (Str_matchOne(str, i, pattern))
            return i;
    return -1;
}

char *Str_lineFromStdin()
{
    ListType *list = ListType_ListType(free);
    while (1)
    {
        int c = getchar();
        if (c == EOF || c == '\n')
            break;
        if (c == '\r')
            continue;
        ListType_insert(list, NULL, newChar(c));
    }
    char *res = Str_fromCharListType(list);
    ListType_free(list);
    return res;
}

char *Str_rJust(const char *origin, int len, char ch)
{
    int justLen = len - strlen(origin);
    if (justLen > 0)
    {
        char *res = malloc((justLen + 1) * sizeof(char));
        for (int i = 0; i < justLen; i++)
            res[i] = ch;
        res[justLen] = 0;
        return Str_addFree(res, Str_clone(origin));
    }
    else
    {
        return Str_clone(origin);
    }
}
char *Str_rJustFree(char *origin, int len, char ch)
{
    char *res = Str_rJust(origin, len, ch);
    free(origin);
    return res;
}
